function $_vituaList_InitPlugin($__optimize) {
  // 二分搜索--->根据top值返回索引
  function $_binarySearch(list, value) {
    var left = 0;
    var right = list.length - 1;
    var tempIndex = null;
    while (left <= right) {
      var mid = Math.floor((left + right) / 2);
      var midValue = list[mid].bottom;
      if (midValue === value) {
        return mid + 1;
      } else if (midValue > value) {
        if (tempIndex === null || tempIndex > mid) {
          tempIndex = mid;
        }
        right--;
      } else if (midValue < value) {
        left = mid + 1;
      }
    }
    return tempIndex;
  }
  // 列表props
  const list = {
    type: Array,
    required: true,
    default() {
      return [];
    },
  };
  // 预估高度props
  const estimateHeight = {
    type: Number,
    default() {
      return 50;
    },
  };
  // 基础容器基础样式
  const containerBaseStyle = {
    overflow: "auto",
    position: "relative",
  };
  // 撑版容器基础样式
  const boardContainerBaseStyle = {
    "z-index": -1,
    position: "absolute",
    top: "0",
    left: "0",
    right: "0",
  };
  // 渲染容器基础样式
  const renderContainerBaseStyle = {
    position: "absolute",
    top: "0",
    left: "0",
  };
  // 组件对象
  const virtualList = {
    name: "virtual-list",
    // 模板选项
    template: `
  <div :style = "containerBaseStyle" @scroll="scrollHandle" ref="container">
    <div :style = "[boardContainerBaseStyle,calTotalHeight]"></div>
    <div :style = "renderContainerBaseStyle">
      <div 
        v-for="item in renderList" 
        :style = "setTranslate"
        :key = "item.id"
        ref = "renderlist">
        {{item.content}}
      </div>
    </div>
  </div>
  `,
    props: {
      // 注册props
      list,
      estimateHeight,
    },
    data() {
      // 数据选项
      return {
        containerBaseStyle,
        boardContainerBaseStyle,
        renderContainerBaseStyle,
        listData: Object.freeze(this.list), // 冻结传入的列表props，节省性能开销
        // renderListData: [], // 实际渲染的列表
        listPositionsInfo: [],
        firstRenderIndex: 0,
        clientContainerHeight: 0,
      };
    },
    computed: {
      // 计算属性选项
      calTotalHeight() {
        return {
          height:
            this.listPositionsInfo[this.listPositionsInfo.length - 1].bottom +
            "px",
        };
      },
      // 设置偏移量算法
      setTranslate() {
        const topValue = this.listPositionsInfo[this.firstRenderIndex].top;
        return {
          transform: `translate3d(0,${topValue}px,0)`,
        };
      },
      lastRenderIndex() {
        return (
          this.firstRenderIndex +
          Math.ceil(this.clientContainerHeight / this.estimateHeight)
        );
      },
      renderList() {
        return this.addArrayId(
          this.listData.slice(this.firstRenderIndex, this.lastRenderIndex + 1),
          this.firstRenderIndex
        );
      },
    },
    created() {
      // 创建声明周期钩子
      for (let i = 0; i < this.list.length; i++) {
        // 初始化位置信息
        this.listPositionsInfo.push({
          index: i,
          height: this.estimateHeight,
          top: i * this.estimateHeight,
          bottom: (i + 1) * this.estimateHeight,
        });
      }
    },
    mounted() {
      // 挂载阶段钩子
      // 初始化可视区高度信息
      this.$nextTick(() => {
        this.clientContainerHeight = this.$refs.container.clientHeight;
      });
    },
    updated() {
      // 更新阶段钩子
      this.$nextTick(() => {
        // 更新位置信息数组
        const renderlist = this.$refs.renderlist;
        let index = this.firstRenderIndex;
        renderlist.forEach((el) => {
          this.calCompensation(el, index);
          index++;
        });
      });
    },
    methods: {
      // 方法选项
      // 处理滚动事件函数
      scrollHandle: $__optimize(function(e) {
        // console.log(e.target.scrollTop);
        let scrollDis = e.target.scrollTop;
        // 计算首尾索引并切片原数据
        this.firstRenderIndex = $_binarySearch(
          this.listPositionsInfo,
          scrollDis
        );
      }),
      // 计算滚动补偿差值
      calCompensation(el, index) {
        let rect = el.getBoundingClientRect();
        let height = rect.height;
        let previousHeight = this.listPositionsInfo[index].height;
        let dValue = previousHeight - height; // 计算出差值
        if (dValue) {
          this.listPositionsInfo[index].bottom =
            this.listPositionsInfo[index].bottom - dValue;
          this.listPositionsInfo[index].height = height;
          // --->更新后续的位置信息
          for (let i = index + 1; i < this.listPositionsInfo.length; i++) {
            this.listPositionsInfo[i].top = this.listPositionsInfo[
              i - 1
            ].bottom;
            this.listPositionsInfo[i].bottom =
              this.listPositionsInfo[i].bottom - dValue;
          }
        }
      },
      // 为数组绑定ID
      addArrayId(array, index) {
        return array.map((elem) => {
          index++;
          return {
            content: elem,
            id: "_" + (index - 1),
          };
        });
      },
    },
  };
  return virtualList;
}
// 暴露插件
const virtualListPlugin = {
  install(Vue, options) {
    // 按固定时间节流
    function $_throttleBytime(callback, delay = 300) {
      let timeId = null;
      return function(...params) {
        if (timeId) clearTimeout(timeId);
        timeId = setTimeout(() => {
          callback.apply(this, params);
        }, delay);
      };
    }
    // 按帧防抖
    function $_debounceByFrame(callback) {
      let canRun = true;
      return function(...params) {
        if (!canRun) {
          return;
        }
        canRun = false;
        callback.apply(this, params);
        requestAnimationFrame(() => {
          canRun = true;
        });
      };
    }
    const COMPONENT_NAME = "virtual-list";
    let useFrameOptimize = options ? options.useFrameOptimize : false;
    const $__optimize = useFrameOptimize ? $_debounceByFrame : $_throttleBytime;
    Vue.component(COMPONENT_NAME, $_vituaList_InitPlugin($__optimize)); // 全局注册虚拟列表组件
  },
};
